/*
 * File     : X86_64ThunkManagerDelegate.java
 * Created  : 7 Jan 2012
 *
 * Copyright © 2011 Matthew Wilson (mj. {my-surname} .uk {at} gmail.com)
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.googlecode.dni.internal.callback;

import java.lang.reflect.Method;

import com.googlecode.dni.internal.DniInternal;
import com.googlecode.dni.internal.callback.ThunkManager.ThunkManagerDelegate;

/**
 * Implementation of {@link ThunkManagerDelegate}.
 *
 * @author Matthew Wilson
 */
abstract class AbstractThunkManagerDelegate implements ThunkManagerDelegate
{

    /**
     * The native code's idea of the entry size.
     */
    static final int NATIVE_ENTRY_SIZE = getEntrySize();

    private static final int JAVA_VM = 1;
    private static final int IMPL_TYPE = 2;
    private static final int HELPER_METHOD = 4;
    private static final int DELEGATE = 8;
    private static final int WRONG_DELEGATE = 16;


    /** {@inheritDoc} */
    @Override
    public final void fillEntry( final long infoAddress, final Class< ? > implType, final Method helperMethod, final Object delegate )
    {
        fillEntryImpl( infoAddress, implType, helperMethod, delegate );
    }

    /** {@inheritDoc} */
    @Override
    public final void clearEntry( final long infoAddress, final Object delegate )
    {
        int result = clearEntryImpl( infoAddress, delegate );
        if ( result != 0 )
        {
            logError( infoAddress, delegate, result );
        }
    }

    private static void logError( final long infoAddress, final Object delegate, final int result )
    {
        StringBuilder str = new StringBuilder();
        str.append( "Assertion error: cleared incorrect thunk entry; " );

        if ( ( result & JAVA_VM ) != 0 )
        {
            str.append( "wrong JavaVM; " );
        }
        if ( ( result & IMPL_TYPE ) != 0 )
        {
            str.append( "wrong class; " );
        }
        if ( ( result & HELPER_METHOD ) != 0 )
        {
            str.append( "wrong method; " );
        }
        if ( ( result & DELEGATE ) != 0 )
        {
            str.append( "bad delegate; " );
        }
        if ( ( result & WRONG_DELEGATE ) != 0 )
        {
            str.append( "wrong delegate; " );
        }

        str.append( Long.toHexString( infoAddress ) )
           .append( " " )
           .append( delegate );

       DniInternal.LOGGER.severe( str.toString() );
    }

    /**
     * @return the native code's idea of the entry size
     */
    private static native int getEntrySize();

    private static native void fillEntryImpl( long infoAddress,
                                              Class< ? > implType,
                                              Method helperMethod,
                                              Object delegate );

    private static native int clearEntryImpl( long infoAddress, Object delegate );

}
